﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Evolution
{
    class CEvol
    {
        sbyte[,] a = new sbyte[32, 32]; //our field
        public CEvol()
        {
            generate(); //constructor generate new field    
        }
        void generate()
        {

            Random rnd = new Random();
            for (int i = 0; i < 32; ++i) //it will be a frame around matrix with a null-weight, to simplify evaluations
            {
                a[0, i] = 0;
                a[0, i] = 0;
                a[31, i] = 0;
                a[i, 31] = 0;
            }
            for (int i = 1; i < 31; ++i)
                for (int j = 1; j < 31; ++j)
                {
                    if (rnd.Next(0, 2) == 1)
                        a[i, j] = 8;  // if it is a life cell, it gains 8 weight. It important to test nearby cells by rules
                    else
                        a[i, j] = 1;
                }
        }

        /// <summary>
        /// return's sum of a frame-elements for current
        /// </summary>
        /// <param name="i">row of element</param>
        /// <param name="j">column of element</param>
        /// <returns>sum of a frame-elements for current</returns>
        int nearSum(int i, int j)
        { 
            return a[i - 1, j - 1] + a[i, j - 1] + a[i - 1, j] + a[i, j + 1] + a[i + 1, j] + a[i + 1, j + 1] + a[i - 1, j + 1] + a[i + 1, j - 1];
        }

        /// <summary>
        /// the Async Cycle means that all alive cells will be produced themselves in the one moment
        /// independently
        /// </summary>
        public void NextAsyncCycle()
        { 
            sbyte[,] b = new sbyte[32, 32];//it will be a back-matrix, which saves the field
            Array.Copy(a, b,b.Length);//adding a frame around back-matrix

            for (int i = 1; i < 31; ++i)
                for (int j = 1; j < 31; ++j)
                {
                    //if there are at least 2 cells with the weight=8 then current cell became alive
                    if ((a[i, j] == 1) && (nearSum(i, j) >= 16))
                    {
                        b[i, j] = 8;
                    }
                    else
                        //if this cell is already alive, and there only alive cells around,the sum of weight will be evenly divisible by 8.
                        if ((a[i, j] == 8) && ((nearSum(i, j) % 8 == 0) && (nearSum(i, j) != 8)))
                        {
                            b[i, j] = 1; //and of course, if sum is 8, we have only 8 empty cells around.
                        }
                }
            Array.Copy(b, a, b.Length);
        }

        /// <summary>
        /// the Sync Cycle means, that all alive cells wiil be produced themselves consistently, from
        /// left top to right bottom corner.
        /// </summary>
        public void NextSyncCycle()
        {
            for (int i = 1; i < 31; ++i)
                for (int j = 1; j < 31; ++j)
                {
                    //if there are at least 2 cells with the weight=8 then current cell became alive
                    if ((a[i, j] == 1) && (nearSum(i, j) >= 16))
                    {
                        a[i, j] = 8;
                    }
                    else
                        //if this cell is already alive, and there only alive cells around,the sum of weight will be evenly divisible by 8.
                        if ((a[i, j] == 8) && ((nearSum(i, j) % 8 == 0) && (nearSum(i, j)!=8)))
                        {
                            a[i, j] = 1; //and of course, if sum is 8, we have only 8 empty cells around.
                        }
                }
        }

        /// <summary>
        /// Prints matrix to screen
        /// </summary>
        public void print()
        {
            for (int i = 1; i < 31; ++i)
            {
                for (int j = 1; j < 31; ++j)
                {
                    if (a[i, j] == 8)
                        Console.Write("*");//we print * if cell is alive,
                    else
                        Console.Write(" ");//and space else.
                }
                Console.WriteLine();
            }
        }
    }
    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("Hello! It is a little evolution simulator.");
            Console.WriteLine("To start it from new state press N");
            Console.WriteLine("To continue it to next step press SPACE");
            Console.WriteLine("To get a help press H");
            Console.WriteLine("Press E for exit");
            ConsoleKeyInfo key=new ConsoleKeyInfo();
            CEvol MyEvol=null;
            key=Console.ReadKey();
            char ckey = key.KeyChar;
            while ((ckey != 'E') && (ckey != 'e'))
            {
                switch (ckey)
                { 
                    case 'N':
                    case 'n':
                        MyEvol = new CEvol();
                        Console.Clear();
                        MyEvol.print();
                        break;
                    case ' ':
                        MyEvol = MyEvol ?? new CEvol();
                        MyEvol.NextAsyncCycle();
                        Console.Clear();
                        MyEvol.print();

                        break;
                    case 'H':
                    case 'h':
                        Console.Clear();
                        Console.WriteLine("This is evolution program.");
                        Console.WriteLine("It contains a field 30x30 cells. Cells can contain a life object(lo) or\nbeing empty");
                        Console.WriteLine("Each turn lo obey the same rules: ");
                        Console.WriteLine("First, if cell is empty, and there are 2 or more lo in surrounding cells,\ncell become lo.");
                        Console.WriteLine("Second, if cell is lo, and there are no empty cells near from it, lo die\nand cell become empty.");
                        Console.WriteLine("Have a good time with it!");
                        break;
                    default: Console.WriteLine("Unexpected command.");
                        break;
                }
                key = Console.ReadKey();
                ckey = key.KeyChar;
            }
        }
    }
}
